//login:sm2加密算法

//init
init: function (t, e) {
    t = this.words = t || [],
        e != r ? this.sigBytes = e : this.sigBytes = 4 * t.length
}

//h.parse
parse: function (t) {
    for (var r = t.length, e = [], i = 0; i < r; i++)
        e[i >>> 2] |= (255 & t.charCodeAt(i)) << 24 - i % 4 * 8;
    return new s.init(e, r)
}

//CryptoJS.enc.Utf8.parse
parse: function (t) {
    return h.parse(unescape(encodeURIComponent(t)))
}


//
clamp: function () {
    var r = this.words
        , e = this.sigBytes;
    r[e >>> 2] &= 4294967295 << 32 - e % 4 * 8,
        r.length = t.ceil(e / 4)
}

a.enc.Base64 = {
    stringify: function (a) {
        var b = a.words,
            e = a.sigBytes,
            f = this._map;
        a.clamp();
        a = [];
        for (var g = 0; g < e; g += 3)
            for (var h = (b[g >>> 2] >>> 24 - g % 4 * 8 & 255) << 16 | (b[g + 1 >>> 2] >>> 24 - (g + 1) % 4 * 8 & 255) << 8 | b[g + 2 >>> 2] >>> 24 - (g + 2) % 4 * 8 & 255, k = 0; 4 > k && g + .75 * k < e; k++)
                a.push(f.charAt(h >>> 6 * (3 - k) & 63));
        if (b = f.charAt(64))
            for (; a.length % 4;)
                a.push(b);
        return a.join("")
    },
    parse: function (a) {
        var d = a.length,
            e = this._map,
            f = e.charAt(64);
        f && (f = a.indexOf(f),
        -1 != f && (d = f));
        for (var f = [], g = 0, h = 0; h < d; h++)
            if (h % 4) {
                var k = e.indexOf(a.charAt(h - 1)) << h % 4 * 2,
                    l = e.indexOf(a.charAt(h)) >>> 6 - h % 4 * 2;
                f[g >>> 2] |= (k | l) << 24 - g % 4 * 8;
                g++
            }
        return b.create(f, g)
    },
    _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
}

function SM2Cipher(a) {
    this.ct = 1;
    this.sm3c3 = this.sm3keybase = this.p2 = null;
    this.key = Array(32);
    this.keyOff = 0;
    this.cipherMode = "undefined" != typeof a ? a : SM2CipherMode.C1C3C2
}

CreatePoint: function (a, b) {
    var c = new KJUR.crypto.ECDSA({
        curve: "sm2"
    });
    return ECPointFp.decodeFromHex(c.ecparams.curve, "04" + a + b)
}

function nbits(a) {
    var b = 1,
        c;
    0 != (c = a >>> 16) && (a = c,
        b += 16);
    0 != (c = a >> 8) && (a = c,
        b += 8);
    0 != (c = a >> 4) && (a = c,
        b += 4);
    0 != (c = a >> 2) && (a = c,
        b += 2);
    0 != a >> 1 && (b += 1);
    return b
}

//KJUR.crypto.ECDSA
KJUR.crypto.ECDSA
:

function (a) {
    var b = new SecureRandom;
    this.type = "EC";
    this.getBigRandom = function (a) {
        return (new BigInteger(a.bitLength(), b)).mod(a.subtract(BigInteger.ONE)).add(BigInteger.ONE)
    };
    this.setNamedCurve = function (a) {
        this.ecparams = KJUR.crypto.ECParameterDB.getByName(a);
        this.pubKeyHex = this.prvKeyHex = null;
        this.curveName = a
    };
    this.setPrivateKeyHex = function (a) {
        this.isPrivate = !0;
        this.prvKeyHex = a
    };
    this.setPublicKeyHex = function (a) {
        this.isPublic = !0;
        this.pubKeyHex = a
    };
    this.generateKeyPairHex = function () {
        var a = this.getBigRandom(this.ecparams.n),
            b = this.ecparams.G.multiply(a),
            e = b.getX().toBigInteger(),
            b = b.getY().toBigInteger(),
            f = this.ecparams.keylen / 4,
            a = ("0000000000" + a.toString(16)).slice(-f),
            e = ("0000000000" + e.toString(16)).slice(-f),
            b = ("0000000000" + b.toString(16)).slice(-f),
            e = "04" + e + b;
        this.setPrivateKeyHex(a);
        this.setPublicKeyHex(e);
        return {
            ecprvhex: a,
            ecpubhex: e
        }
    };
    this.signWithMessageHash = function (a) {
        return this.signHex(a, this.prvKeyHex)
    };
    this.signHex = function (a, b) {
        var e = new BigInteger(b, 16),
            f = this.ecparams.n,
            g = new BigInteger(a, 16);
        do
            var h = this.getBigRandom(f),
                k = this.ecparams.G.multiply(h).getX().toBigInteger().mod(f);
        while (0 >= k.compareTo(BigInteger.ZERO));
        e = h.modInverse(f).multiply(g.add(e.multiply(k))).mod(f);
        return KJUR.crypto.ECDSA.biRSSigToASN1Sig(k, e)
    };
    this.sign = function (a, b) {
        var e = this.ecparams.n,
            f = BigInteger.fromByteArrayUnsigned(a);
        do
            var g = this.getBigRandom(e),
                h = this.ecparams.G.multiply(g).getX().toBigInteger().mod(e);
        while (0 >= h.compareTo(BigInteger.ZERO));
        e = g.modInverse(e).multiply(f.add(b.multiply(h))).mod(e);
        return this.serializeSig(h, e)
    };
    this.verifyWithMessageHash = function (a, b) {
        return this.verifyHex(a, b, this.pubKeyHex)
    };
    this.verifyHex = function (a, b, e) {
        var f;
        f = KJUR.crypto.ECDSA.parseSigHex(b);
        b = f.r;
        f = f.s;
        e = ECPointFp.decodeFromHex(this.ecparams.curve, e);
        a = new BigInteger(a, 16);
        return this.verifyRaw(a, b, f, e)
    };
    this.verify = function (a, b, e) {
        var f;
        if (Bitcoin.Util.isArray(b))
            b = this.parseSig(b),
                f = b.r,
                b = b.s;
        else if ("object" === typeof b && b.r && b.s)
            f = b.r,
                b = b.s;
        else
            throw "Invalid value for signature";
        if (!(e instanceof ECPointFp))
            if (Bitcoin.Util.isArray(e))
                e = ECPointFp.decodeFrom(this.ecparams.curve, e);
            else
                throw "Invalid format for pubkey value, must be byte array or ECPointFp";
        a = BigInteger.fromByteArrayUnsigned(a);
        return this.verifyRaw(a, f, b, e)
    };
    this.verifyRaw = function (a, b, e, f) {
        var g = this.ecparams.n,
            h = this.ecparams.G;
        if (0 > b.compareTo(BigInteger.ONE) || 0 <= b.compareTo(g) || 0 > e.compareTo(BigInteger.ONE) || 0 <= e.compareTo(g))
            return !1;
        e = e.modInverse(g);
        a = a.multiply(e).mod(g);
        e = b.multiply(e).mod(g);
        return h.multiply(a).add(f.multiply(e)).getX().toBigInteger().mod(g).equals(b)
    };
    this.serializeSig = function (a, b) {
        var e = a.toByteArraySigned(),
            f = b.toByteArraySigned(),
            g = [];
        g.push(2);
        g.push(e.length);
        g = g.concat(e);
        g.push(2);
        g.push(f.length);
        g = g.concat(f);
        g.unshift(g.length);
        g.unshift(48);
        return g
    };
    this.parseSig = function (a) {
        var b;
        if (48 != a[0])
            throw Error("Signature not a valid DERSequence");
        b = 2;
        if (2 != a[b])
            throw Error("First element in signature must be a DERInteger");
        var e = a.slice(b + 2, b + 2 + a[b + 1]);
        b += 2 + a[b + 1];
        if (2 != a[b])
            throw Error("Second element in signature must be a DERInteger");
        a = a.slice(b + 2, b + 2 + a[b + 1]);
        e = BigInteger.fromByteArrayUnsigned(e);
        a = BigInteger.fromByteArrayUnsigned(a);
        return {
            r: e,
            s: a
        }
    };
    this.parseSigCompact = function (a) {
        if (65 !== a.length)
            throw "Signature has the wrong length";
        var b = a[0] - 27;
        if (0 > b || 7 < b)
            throw "Invalid signature type";
        var e = this.ecparams.n,
            f = BigInteger.fromByteArrayUnsigned(a.slice(1, 33)).mod(e);
        a = BigInteger.fromByteArrayUnsigned(a.slice(33, 65)).mod(e);
        return {
            r: f,
            s: a,
            i: b
        }
    };
    void 0 !== a && void 0 !== a.curve && (this.curveName = a.curve);
    void 0 === this.curveName && (this.curveName = "secp256r1");
    this.setNamedCurve(this.curveName);
    void 0 !== a && (void 0 !== a.prv && this.setPrivateKeyHex(a.prv),
    void 0 !== a.pub && this.setPublicKeyHex(a.pub))
}

ECPointFp.decodeFromHex = function (a, b) {
    b.substr(0, 2);
    var c = b.length - 2,
        d = b.substr(2, c / 2),
        c = b.substr(2 + c / 2, c / 2),
        d = new BigInteger(d, 16),
        c = new BigInteger(c, 16);
    return new ECPointFp(a, a.fromBigInteger(d), a.fromBigInteger(c))
};

//
function intAt(a, b) {
    var c = BI_RC[a.charCodeAt(b)];
    return null == c ? -1 : c
}


function BigInteger(a, b, c) {
    null != a && ("number" == typeof a ? this.fromNumber(a, b, c) : null == b && "string" != typeof a ? this.fromString(a, 256) : this.fromString(a, b))
}

function ECPointFp(a, b, c, d) {
    this.curve = a;
    this.x = b;
    this.y = c;
    this.z = null == d ? BigInteger.ONE : d;
    this.zinv = null
}


stringify: function (t) {
    for (var r = t.words, e = t.sigBytes, i = [], n = 0; n < e; n++) {
        var o = r[n >>> 2] >>> 24 - n % 4 * 8 & 255;
        i.push((o >>> 4).toString(16)),
            i.push((15 & o).toString(16))
    }
    return i.join("")
}
toString: function (t) {
    return (t || c).stringify(this)
}

function bnpFromString(a, b) {
    var c;
    if (16 == b)
        c = 4;
    else if (8 == b)
        c = 3;
    else if (256 == b)
        c = 8;
    else if (2 == b)
        c = 1;
    else if (32 == b)
        c = 5;
    else if (4 == b)
        c = 2;
    else {
        this.fromRadix(a, b);
        return
    }
    this.s = this.t = 0;
    for (var d = a.length, e = !1, f = 0; 0 <= --d;) {
        var g = 8 == c ? a[d] & 255 : intAt(a, d);
        0 > g ? "-" == a.charAt(d) && (e = !0) : (e = !1,
            0 == f ? this[this.t++] = g : f + c > this.DB ? (this[this.t - 1] |= (g & (1 << this.DB - f) - 1) << f,
                this[this.t++] = g >> this.DB - f) : this[this.t - 1] |= g << f,
            f += c,
        f >= this.DB && (f -= this.DB))
    }
    8 == c && 0 != (a[0] & 128) && (this.s = -1,
    0 < f && (this[this.t - 1] |= (1 << this.DB - f) - 1 << f));
    this.clamp();
    e && BigInteger.ZERO.subTo(this, this)
}


GetWords: function (a) {
    for (var b = [], c = a.length, d = 0; d < c; d += 2)
        b[b.length] = parseInt(a.substr(d, 2), 16);
    return b
}
Encrypt: function (a, b) {
    var c = Array(b.length);
    Array.Copy(b, 0, c, 0, b.length);
    var d = this.InitEncipher(a);
    this.EncryptBlock(c);
    var e = Array(32);
    this.Dofinal(e);
    for (var f = d.getX().toBigInteger().toRadix(16), d = d.getY().toBigInteger().toRadix(16); 64 > f.length;)
        f = "0" + f;
    for (; 64 > d.length;)
        d = "0" + d;
    f += d;
    c = this.GetHex(c).toString();
    0 != c.length % 2 && (c = "0" + c);
    e = this.GetHex(e).toString();
    d = f + c + e;
    this.cipherMode == SM2CipherMode.C1C3C2 && (d = f + e + c);
    return d
}

Array.Copy = function (a, b, c, d, e) {
    a = a.slice(b, b + e);
    for (b = 0; b < a.length; b++)
        c[d] = a[b],
            d++
};
InitEncipher: function (a) {
    var b = null,
        c = null,
        c = new KJUR.crypto.ECDSA({
            curve: "sm2"
        }),
        d = c.generateKeyPairHex(),
        b = new BigInteger(d.ecprvhex, 16),
        c = ECPointFp.decodeFromHex(c.ecparams.curve, d.ecpubhex);
    this.p2 = a.multiply(b);
    this.Reset();
    return c
}
,

function sm2Encrypt(data, publickey, cipherMode) {
    cipherMode = cipherMode == 0 ? cipherMode : 1;
    // msg = SM2.utf8tob64(msg);
    var msgData = CryptoJS.enc.Utf8.parse(data);

    msgData = CryptoJS.enc.Base64.stringify(msgData);
    //在转utf-8
    msgData = CryptoJS.enc.Utf8.parse(msgData);

    var pubkeyHex = publickey;
    if (pubkeyHex.length > 64 * 2) {
        pubkeyHex = pubkeyHex.substr(pubkeyHex.length - 64 * 2);
    }
    var xHex = pubkeyHex.substr(0, 64);
    var yHex = pubkeyHex.substr(64);
    var cipher = new SM2Cipher(cipherMode);
    var userKey = cipher.CreatePoint(xHex, yHex);
    msgData = cipher.GetWords(msgData.toString());
    var encryptData = cipher.Encrypt(userKey, msgData);

    return '04' + encryptData;
}

encryptSM2: function (t, e) {
    if (e = e || Util.getFrameSysParam("security_sm2encode_pubk"),
        !e)
        throw new Error("the second param [sm2PubKey] can not be empty");
    return t = sm2Encrypt(t, e, 0)
}